package model.graphic.objects;

import model.graphic.objects.addons.RemoveAddon;
import model.graphic.objects.addons.ShrinkAddon;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.io.Serializable;
import java.util.ArrayList;
import model.graphic.GraphicModel;
import model.graphic.locations.AbsoluteLocation;
import model.graphic.locations.Location;
import model.graphic.objects.addons.ZoomAddon;
import view.GUI.LabelReader;
import view.GUI.graphic.SkinInfo;
import view.GUI.graphic.SkinReader;

/**
 *
 * @author Jelle, rewritten by Ben
 */
public class GBoxNode extends RectangleGraphical implements Serializable, Cloneable {

    private GraphicModel gmodel;
    private ZoomAddon zoomAddon;
    private ArrayList<Graphical> transmitters;

    public GBoxNode(String name, Location location, int x, int y) {
        super(name, location, x, y);
        this.setType("BoxNode");
        gmodel = new GraphicModel(this);
        zoomAddon = new ZoomAddon();
        transmitters = new ArrayList<Graphical>();
    }

    @Override
    public GBoxNode clone() {
        GBoxNode gb = (GBoxNode) super.clone();
        gb.setRemoveAddon(new RemoveAddon());
        gb.setShrinkAddon(new ShrinkAddon());
        gb.setZoomAddon(new ZoomAddon());
        gb.setResizer(null);
        gb.setTransmitterObjects(new ArrayList<Graphical>());
        gb.setGraphicModel(new GraphicModel(gb));
        for(Graphical g : this.getGraphicModel().getObjects()){
            gb.addInternalObject(g);
        }
        for(Graphical g : this.getTransmitterObjects()){
            gb.addTransmitterObject(g);
        }
        return gb;
    }

    public GraphicModel getGraphicModel() {
        return gmodel;
    }

    public void setGraphicModel(GraphicModel gmodel) {
        this.gmodel = gmodel;
    }

    @Override
    public void paint(Graphics2D g) {
        if(this.isVisible()){
            SkinInfo info = SkinReader.getInstance().getSkinInfo(LabelReader.noTemplate(type));
            Color oldColor = g.getColor();
            Stroke oldStroke = g.getStroke();
            getRemoveAddon().setCenter(new AbsoluteLocation(lowerRight.getX() - 10, lowerRight.getY() - 10));
            getShrinkAddon().setCenter(location);
            getZoomAddon().setCenter(new AbsoluteLocation(lowerRight.getX(), lowerRight.getY() - getHeight()));

            this.drawSkin(info, g);

            if (highlighted || selected) {
                g.setColor(highlightColor);
            } else {
                g.setColor(baseColor);
            }
            g.setStroke(new BasicStroke(2));
            g.drawRect(location.getX(), location.getY(), getWidth(), getHeight());
            g.setStroke(new BasicStroke(1));
            g.drawLine(location.getX(), location.getY() + getHeight() / 3, location.getX() + getWidth(), location.getY() + getHeight() / 3);

            if (name != null) {
                g.setColor(Color.BLACK);
                if (getWidth() / 10 + 1 <= name.length()) {
                    drawCentered(g, name.substring(0, getWidth() / 10) + "...", new Rectangle(location.getX(), location.getY(), getWidth(), getHeight() / 3));
                } else {
                    drawCentered(g, name, new Rectangle(location.getX(), location.getY(), getWidth(), getHeight() / 3));
                }
            }
            if (type != null) {
                g.setColor(Color.BLACK);
                if (getWidth() / 10 + 1 <= type.length()) {
                    drawCentered(g, type.substring(0, getWidth() / 10) + "...", new Rectangle(location.getX(), location.getY() + getHeight() / 3, getWidth(), getHeight() / 3));
                } else {
                    drawCentered(g, type, new Rectangle(location.getX(), location.getY() + getHeight() / 3, getWidth(), getHeight() / 3));
                }
            }
            g.setStroke(oldStroke);

            if (!getShrinkAddon().isAddonHighlighted()) {
                g.setStroke(oldStroke);
                g.setColor(Color.RED);
            } else {
                g.setStroke(new BasicStroke(4.0f));
                g.setColor(Color.BLUE);
            }

            if (!getShrinkAddon().isShrinked()) {
                g.draw(getShrinkAddon().getL1());

            } else {
                g.draw(getShrinkAddon().getL1());
                g.draw(getShrinkAddon().getL2());
            }
            if (!getRemoveAddon().isAddonHighlighted()) {
                g.setStroke(oldStroke);
                g.setColor(Color.RED);
            } else {
                g.setStroke(new BasicStroke(4.0f));
                g.setColor(Color.BLUE);
            }
            g.draw(getRemoveAddon().getL1());
            g.draw(getRemoveAddon().getL2());

            if (!zoomAddon.isAddonHighlighted()) {
                g.setStroke(oldStroke);
                g.setColor(Color.RED);
            } else {
                g.setStroke(new BasicStroke(4.0f));
                g.setColor(Color.BLUE);
            }

            g.draw(getZoomAddon().getL1());
            g.draw(getZoomAddon().getL2());
            g.draw(getZoomAddon().getL3());

            g.setColor(oldColor);
            g.setStroke(oldStroke);
        }
    }

    public void addInternalObject(Graphical g) {
       gmodel.addObject(g);
    }

    public void removeInternalObject(Graphical g) {
        gmodel.removeObject(g);
    }

    public void addTransmitterObject(Graphical g) {
        transmitters.add(g);
    }

    public void removeTransmitterObject(Graphical g) {
        transmitters.remove(g);
    }

    public ArrayList<Graphical> getAttachedObjects(GNode gn) {
        ArrayList<Graphical> ar = new ArrayList<Graphical>();
        for (Graphical g : getInternalObjects()) {
            if (Attachment.class.isAssignableFrom(g.getClass())) {
                Attachment gh = (Attachment) g;
                if (gh.getBase().equals(gn)) {
                    ar.add(g);
                }
            }
        }
        return ar;
    }

    public ArrayList<Graphical> getAttachments(GNode gn) {
        ArrayList<Graphical> setb = new ArrayList<Graphical>();
        for (Graphical g : getAttachedObjects(gn)) {
            setb.add((Attachment) g);
            for (Graphical g2 : getInternalObjects()) {
                if (Attachment.class.isAssignableFrom(g2.getClass())) {
                    Attachment gh = (Attachment) g2;
                    if (gh.getBase().equals(g)) {
                        setb.add((Attachment) g2);
                    }
                }
            }
        }
        return setb;
    }

    public void removeInternalNode(GNode gn) {
        for (Graphical g : getAttachments(gn)) {
            removeInternalObject(g);
        }
        removeInternalObject(gn);
    }

    public void printInternals() {
        System.out.println("printInternals");
        for (Graphical g : getInternalObjects()) {
            System.out.println("\t" + g.getClass().getSimpleName());
        }
    }

    /**
     * @return the objects
     */
    public ArrayList<Graphical> getInternalObjects() {
        return gmodel.getAllObjects();
    }

    /**
     * @param objects the objects to set
     */
    public void setInternalObjects(ArrayList<Graphical> objects) {
        gmodel.removeAll();
        for(Graphical g : objects){
            gmodel.addObject(g);
        }
    }

    /**
     * @return the transmitterObjects
     */
    public ArrayList<Graphical> getTransmitterObjects() {
        return transmitters;
    }

    /**
     * @param transmitterObjects the transmitterObjects to set
     */
    public void setTransmitterObjects(ArrayList<Graphical> transmitterObjects) {
        this.transmitters = transmitterObjects;
    }

    /**
     * @return the zoomAddon
     */
    public ZoomAddon getZoomAddon() {
        return zoomAddon;
    }

    /**
     * @param zoomAddon the zoomAddon to set
     */
    public void setZoomAddon(ZoomAddon zoomAddon) {
        this.zoomAddon = zoomAddon;
    }
}